package com.hb.common.handler.backup;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.FileUtil;
import com.sl.ecm.backup.dto.Database;
import com.sl.ecm.backup.exception.DbBackupException;
import com.sl.ecm.backup.util.CommonUtil;
import com.sl.ecm.backup.util.OSUtil;
import com.sl.ecm.backup.util.PathPermissions;
import com.sl.ecm.backup.util.ShellExecutorUtil;
import com.sl.ecm.backup.ws.BackupEndpoint;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.annotation.Resource;
import java.io.File;
import java.util.Date;
import java.util.concurrent.atomic.AtomicReference;

/**
 * 抽象类，提供备份和还原的通用实现
 */
public abstract class AbstractDbBackupHandler implements DbBackupHandler {

    private static final Logger log = LoggerFactory.getLogger(AbstractDbBackupHandler.class);

    @Resource
    protected OSUtil osUtil;
    @Resource
    protected PathPermissions pathPermissions;

	@Resource
	protected BackupEndpoint chatEndpoint;

    /**
     * 执行备份操作
     *
     * @param database 数据源信息
     * @param id
	 * @return 备份是否成功
     * @throws DbBackupException 备份过程中可能抛出的异常
     */
    @Override
    public boolean backup(Database database, Integer id) throws DbBackupException {
        // 获取备份文件存放目录
        String dbBackupPath = pathPermissions.getDbBackupPath(database);
        // 备份文件名称
        String dbFileName = dbFileName(database);
        // 完整的备份文件路径
        String dbFilePath = dbBackupPath + dbFileName;
        log.info("备份文件路径{}", dbFilePath);
        // 创建备份命令
        String[] command = createBackupCommand(database, dbFilePath);
        // 数据库程序路径
        String dbProgramPath = dbProgramPath();
        if (!new File(dbProgramPath).exists()) {
            throw new DbBackupException("备份失败: 不支持的系统环境");
        }
        // 执行备份命令

		// 记录异常信息
		AtomicReference<String> failMsg = new AtomicReference<>();
        try {
			int exit = ShellExecutorUtil.execute(command, dbProgramPath, 0L,(msg, process) -> {
				chatEndpoint.sendMessageToUser(String.valueOf(id),msg);
				failMsg.set(msg);
			});
			if (exit != 0) {
				throw new DbBackupException(failMsg.get());
			}
			backupAfter(dbFilePath);
        } catch (Exception e) {
            // 备份失败时删除已创建的备份文件
            FileUtil.del(dbFilePath);
			backupAfter(dbFilePath);
            throw new DbBackupException("备份失败: " + e.getMessage(), e);
        }
        CommonUtil.manageFiles(dbBackupPath, database.getMaxFileNum());
        return true;
    }



    /**
     * 执行还原操作
     *
     * @param database   数据源信息
     * @param dbFilePath 备份文件完整路径
     * @param id
	 * @return 还原是否成功
     * @throws DbBackupException 还原过程中可能抛出的异常
     */
    @Override
    public boolean restore(Database database, String dbFilePath, Integer id) throws DbBackupException {
        // 创建还原命令
        String[] command = createRestoreCommand(database, dbFilePath);
        // 数据库程序路径
        String dbProgramPath = dbProgramPath();
		// 记录异常信息
		AtomicReference<String> failMsg = new AtomicReference<>();
        // 执行还原命令
        try {
            int exit = ShellExecutorUtil.execute(command, dbProgramPath,0L,(msg, process) -> {
				chatEndpoint.sendMessageToUser(String.valueOf(id),msg);
				failMsg.set(msg);
			});
			if (exit != 0) {
				throw new DbBackupException(failMsg.get());
			}
			restoreAfter(dbFilePath);
        } catch (Exception e) {
			restoreAfter(dbFilePath);
            throw new DbBackupException("还原失败: " + e.getMessage(), e);
        }
        return true;
    }
	protected abstract void backupAfter(String dbBackupPath);
	protected abstract void restoreAfter(String dbProgramPath);
    //==========================================

    /**
     * 创建备份命令（由子类实现）
     *
     * @param database   数据源信息
     * @param dbFilePath 备份文件路径
     * @return 备份命令字符串
     */
    protected abstract String[] createBackupCommand(Database database, String dbFilePath) throws DbBackupException;

    /**
     * 创建还原命令（由子类实现）
     *
     * @param database   数据源信息
     * @param dbFilePath 还原文件路径
     * @return 还原命令字符串
     */
    protected abstract String[] createRestoreCommand(Database database, String dbFilePath) throws DbBackupException;

    /**
     * 数据库程序路径（由子类实现）
     *
     * @return 数据库程序路径
     */
    protected abstract String dbProgramPath();

    /**
     * 备份文件后缀
     * @return
     */
    protected abstract String dbFileTye();
    /**
     * 提供默认的备份文件名称（子类可按需重写）
     *
     * @param database 数据源信息
     * @return 备份文件名
     */
    protected String dbFileName(Database database) {
        // 生成备份文件名
        return database.getDbName()
                + DateUtil.format(new Date(), "yyyyMMddHHmmss")
                + "." + dbFileTye();
    }


}
